﻿using System;
using System.Collections.Generic;
using System.IO;
using Generator;
using Ratings;
using System.Linq;

namespace Test
{
    class Program
    {
        private const string generatedRatingsPath = "generatedRatings.dat";
        private const int userN = 6041;
        private const int movieN = 3953;
        private const double RMSE = 0.87244617306302807;

        private static int GetGeneratedRating(int userId, int movieId)
        {
            FileStream fs = new FileStream(generatedRatingsPath, FileMode.Open);
            int position = userId * movieN + movieId;
            fs.Seek(position, SeekOrigin.Begin);
            int res = fs.ReadByte();
            fs.Close();
            return res;
        }

        private static IEnumerable<int> GetMoviesWithRating(int userId, int rating)
        {
            FileStream fs = new FileStream(generatedRatingsPath, FileMode.Open);
            int position = userId * movieN + 1;
            fs.Seek(position, SeekOrigin.Begin);
            for (int i = 1; i < movieN; i++)
            {
                int currentRating = fs.ReadByte();
                if (currentRating == rating)
                {
                    yield return i;
                }
            }
            fs.Close();
        }

        
        private static double evaluateRMSE()
        {
            int maxUserID = 6040;
            int maxMovieID = 3952;
            string pathRatings = "ratings.dat";
            string pathMovies = "movies.dat";
            Parser parser = new Parser();
            Tuple<int[,], Dictionary<Tuple<int, int>, int>> ratings = parser.ParseRatings(pathRatings, pathMovies, maxUserID, maxMovieID);
            Dictionary<Tuple<int, int>, int> dictionary = ratings.Item2;
            List<Tuple<int, int>> observedAndPredicted = new List<Tuple<int,int>>();
            foreach (var record in dictionary)
            {
                int userId = record.Key.Item1;
                int movieId = record.Key.Item2;
                int observedRating = record.Value;
                int predictedRating = GetGeneratedRating(userId, movieId);
                observedAndPredicted.Add(new Tuple<int, int>(observedRating, predictedRating));
            }
            
            double sum = 0;
            foreach (var t in observedAndPredicted)
            {
                sum += Math.Pow((t.Item1 - t.Item2), 2);
            }

            double res = Math.Sqrt(sum / observedAndPredicted.Count);
            return res;
        }

        static void Main(string[] args)
        {

            Console.WriteLine("Hi! This is recomend system for the movie database.\nRMSE: {0}\n", RMSE);
            Console.WriteLine("Choose an option:\n");
            while (true)
            {

                Console.WriteLine("1  -  will show you recomended rating\n for the user and the movie you are interested");
                Console.WriteLine("2  -  will show you all movies that have rating for movie you are interested");
                Console.WriteLine("3 -   will close this program");
                int answer;
                if (!int.TryParse(Console.ReadLine(), out answer))
                {
                    Console.WriteLine("Nope");
                    Console.ReadLine();
                    continue;
                }
                Console.Clear();
                switch (answer)
                {
                    case 1:
                        while (true)
                        {
                            int userId = 0;
                            int movieId = 0;
                            Console.WriteLine("Database has information for 6040 users and 3952 movies\n");
                            Console.WriteLine("Enter user ID");
                            if (!int.TryParse(Console.ReadLine(), out userId))
                            {
                                Console.WriteLine("Nope");
                                Console.ReadLine();
                                continue;
                            }
                            Console.WriteLine("\nEnter movie ID");
                            if (!int.TryParse(Console.ReadLine(), out movieId))
                            {
                                Console.WriteLine("Nope");
                                Console.ReadLine();
                                continue;
                            }

                            if (!(userId > 0 && userId < userN && movieId > 0 && movieId < userN))
                            {
                                Console.WriteLine("\nNope. Invalid ids.");
                                Console.ReadLine();
                                Console.Clear();
                                continue;
                            }
                            int rating = GetGeneratedRating(userId, movieId);
                            Console.WriteLine("\nWell, this is the rating {0}", rating);
                            Console.ReadLine();
                            break;
                        }
                        break;
                    case 2:
                        while (true)
                        {
                            int userId = 0;
                            int rating = 0;
                            Console.WriteLine("Database has information for 6040 users and movies rated from 1 to 5\n");
                            Console.WriteLine("Enter user ID");
                            if (!int.TryParse(Console.ReadLine(), out userId))
                            {
                                Console.WriteLine("Nope");
                                Console.ReadLine();
                                continue;
                            }
                            Console.WriteLine("\nEnter rating");
                            if (!int.TryParse(Console.ReadLine(), out rating))
                            {
                                Console.WriteLine("Nope");
                                Console.ReadLine();
                                continue;
                            }

                            if (!(userId > 0 && userId < userN && rating > 0 && rating <= 6))
                            {
                                Console.WriteLine("\nNope. Invalid ID or rating");
                                Console.ReadLine();
                                Console.Clear();
                                continue;
                            }
                            var ratings = GetMoviesWithRating(userId, rating).ToArray();
                            if (ratings.Length == 0)
                            {
                                Console.WriteLine("\nThere's no movie with such rating for this user.");
                            }
                            else
                            {
                                Console.WriteLine("\nRated {0} for this user:", rating);
                                foreach (int iRating in ratings)
                                {
                                    Console.Write("{0}  ", iRating);
                                }
                            }
                            Console.ReadLine();
                            break;
                        }
                        break;
                    case 3:
                        Environment.Exit(0);
                        break;
                    default:
                        Console.WriteLine("Nope.");
                        Console.ReadLine();
                        break;
                }
                Console.Clear();
            }
        }
    }
}
